package support;

import cn.hutool.core.bean.BeanUtil;
import com.bugstack.springframework.beans.PropertyValue;
import com.bugstack.springframework.beans.PropertyValues;
import com.bugstack.springframework.beans.factory.config.BeanDefinition;
import com.bugstack.springframework.beans.factory.config.BeanReference;

import java.lang.reflect.Constructor;

public abstract class AbstractAutowireCapableBeanFactory2 extends AbstractBeanFactory{

    //引入获取构造函数的方法
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
        Object bean = null;
        bean =createBeanInstance(beanDefinition,beanName,args);
        applyPropertyValues(bean,beanDefinition,beanName);
        return bean;
    }

    private void applyPropertyValues(Object bean, BeanDefinition beanDefinition, String beanName) {
        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
            Object value = propertyValue.getValue();
            String name = propertyValue.getName();

            if(value instanceof BeanReference ){
                BeanReference beanReference = (BeanReference) value;
                value = getBean(beanName);
            }
            BeanUtil.setFieldValue(bean,name,value);
        }

    }

    private Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
        Constructor constructor = null;
        Class beanClass = beanDefinition.getBeanClass();
        Constructor[] declaredConstructors = beanClass.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            Class[] parameterTypes = declaredConstructor.getParameterTypes();
            if(args!=null && args.length == parameterTypes.length){
                constructor = declaredConstructor;
                break;
            }
        }
        Object bean = getInstantiationStrategy().instantiate(beanDefinition, beanName, constructor, args);

        return bean;
    }

    public InstantiationStrategy getInstantiationStrategy(){
        return instantiationStrategy;
    }
}
